﻿namespace UnityEditor
{
    using System;
    using System.Runtime.CompilerServices;
    using UnityEngine;

    public sealed class EditorApplication
    {
        public static CallbackFunction delayCall;
        private static CallbackFunction delayedCallback;
        internal static CallbackFunction globalEventHandler;
        public static CallbackFunction hierarchyWindowChanged;
        public static HierarchyWindowItemCallback hierarchyWindowItemOnGUI;
        public static CallbackFunction modifierKeysChanged;
        internal static AnimationClipAwake onAnimationClipAwake;
        public static CallbackFunction playmodeStateChanged;
        public static CallbackFunction projectWindowChanged;
        public static ProjectWindowItemCallback projectWindowItemOnGUI;
        private static float s_DelayedCallbackTime;
        public static CallbackFunction searchChanged;
        internal static CallbackFunction undoRedoPerformed;
        public static CallbackFunction update;
        internal static CallbackFunction windowsReordered;

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void Beep();
        internal static void CallDelayed(CallbackFunction function, float timeFromNow)
        {
            delayedCallback = function;
            s_DelayedCallbackTime = Time.realtimeSinceStartup + timeFromNow;
            update = (CallbackFunction) Delegate.Combine(update, new CallbackFunction(EditorApplication.CheckCallDelayed));
        }

        private static void CheckCallDelayed()
        {
            if (Time.realtimeSinceStartup > s_DelayedCallbackTime)
            {
                update = (CallbackFunction) Delegate.Remove(update, new CallbackFunction(EditorApplication.CheckCallDelayed));
                delayedCallback();
            }
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern bool ExecuteMenuItem(string menuItemPath);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        internal static extern bool ExecuteMenuItemOnGameObjects(string menuItemPath, GameObject[] objects);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void Exit(int returnValue);
        private static void Internal_CallAnimationClipAwake(AnimationClip clip)
        {
            if (onAnimationClipAwake != null)
            {
                onAnimationClipAwake(clip);
            }
        }

        private static void Internal_CallDelayFunctions()
        {
            CallbackFunction delayCall = EditorApplication.delayCall;
            EditorApplication.delayCall = null;
            if (delayCall != null)
            {
                delayCall();
            }
        }

        private static void Internal_CallGlobalEventHandler()
        {
            if (globalEventHandler != null)
            {
                globalEventHandler();
            }
            WindowLayout.MaximizeKeyHandler();
            Event.current = null;
        }

        private static void Internal_CallHierarchyWindowHasChanged()
        {
            if (hierarchyWindowChanged != null)
            {
                hierarchyWindowChanged();
            }
        }

        private static void Internal_CallKeyboardModifiersChanged()
        {
            if (modifierKeysChanged != null)
            {
                modifierKeysChanged();
            }
        }

        private static void Internal_CallProjectWindowHasChanged()
        {
            if (projectWindowChanged != null)
            {
                projectWindowChanged();
            }
        }

        internal static void Internal_CallSearchHasChanged()
        {
            if (searchChanged != null)
            {
                searchChanged();
            }
        }

        private static void Internal_CallUndoRedoPerformed()
        {
            if (undoRedoPerformed != null)
            {
                undoRedoPerformed();
            }
        }

        private static void Internal_CallUpdateFunctions()
        {
            if (update != null)
            {
                update();
            }
        }

        private static void Internal_CallWindowsReordered()
        {
            if (windowsReordered != null)
            {
                windowsReordered();
            }
        }

        private static void Internal_PlaymodeStateChanged()
        {
            if (playmodeStateChanged != null)
            {
                playmodeStateChanged();
            }
        }

        private static void Internal_RepaintAllViews()
        {
            foreach (GUIView view in Resources.FindObjectsOfTypeAll(typeof(GUIView)))
            {
                view.Repaint();
            }
        }

        private static void Internal_SwitchSkin()
        {
            EditorGUIUtility.skinIndex = 1 - EditorGUIUtility.skinIndex;
            EditorGUIUtility.look = EditorLook.Uninitialized;
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void LockReloadAssemblies();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void NewScene();
        public static void OpenProject(string projectPath, params string[] args)
        {
            OpenProjectInternal(projectPath, args);
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        private static extern void OpenProjectInternal(string projectPath, string[] args);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern bool OpenScene(string path);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void OpenSceneAdditive(string path);
        public static void RepaintHierarchyWindow()
        {
            foreach (HierarchyWindow window in Resources.FindObjectsOfTypeAll(typeof(HierarchyWindow)))
            {
                window.Repaint();
            }
        }

        public static void RepaintProjectWindow()
        {
            foreach (ObjectBrowser browser in ObjectBrowser.GetAllObjectBrowsers())
            {
                browser.Repaint();
            }
        }

        internal static void RequestRepaintAllViews()
        {
            Internal_RepaintAllViews();
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void SaveAssets();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern bool SaveCurrentSceneIfUserWantsTo();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        internal static extern bool SaveCurrentSceneIfUserWantsToForce();
        public static bool SaveScene()
        {
            bool saveAsCopy = false;
            return SaveScene(string.Empty, saveAsCopy);
        }

        public static bool SaveScene(string path)
        {
            bool saveAsCopy = false;
            return SaveScene(path, saveAsCopy);
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern bool SaveScene(string path, bool saveAsCopy);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        internal static extern void SetSceneRepaintDirty();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void Step();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void UnlockReloadAssemblies();

        public static string applicationContentsPath { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        public static string applicationPath { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        public static string currentScene { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        public static bool isCompiling { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        public static bool isPaused { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] set; }

        public static bool isPlaying { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] set; }

        public static bool isPlayingOrWillChangePlaymode { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        public static bool isUpdating { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        internal static UnityEngine.Object tagManager { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        public static double timeSinceStartup { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }

        internal delegate void AnimationClipAwake(AnimationClip clip);

        public delegate void CallbackFunction();

        public delegate void HierarchyWindowItemCallback(int instanceID, Rect selectionRect);

        public delegate void ProjectWindowItemCallback(string guid, Rect selectionRect);
    }
}

